
///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2002, Perry L. Miller IV
//  All rights reserved.
//  BSD License: http://www.opensource.org/licenses/bsd-license.html
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//
//  Registry database class.
//
///////////////////////////////////////////////////////////////////////////////

#include "Usul/Registry/Database.h"
#include "Usul/Registry/Node.h"
#include "Usul/Registry/Visitor.h"

#include <algorithm>

using namespace Usul::Registry;


///////////////////////////////////////////////////////////////////////////////
//
//  Static data member(s).
//
///////////////////////////////////////////////////////////////////////////////

Database *Database::_instance ( 0x0 );


///////////////////////////////////////////////////////////////////////////////
//
//  Constructor.
//
///////////////////////////////////////////////////////////////////////////////

Database::Database() : 
  _mutex ( new Mutex() ),
  _root  ( new Node() )
{
  _root->name ( "registry" );
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destructor.
//
///////////////////////////////////////////////////////////////////////////////

Database::~Database()
{
  _root = 0x0;
  delete _mutex;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Return the single instance. Not thread safe allocation!
//
///////////////////////////////////////////////////////////////////////////////

Database &Database::instance()
{
  if ( 0x0 == _instance )
    _instance = new Database;
  return *_instance;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destroy the single instance. Not thread safe!
//
///////////////////////////////////////////////////////////////////////////////

void Database::destroy()
{
  if ( 0x0 != _instance )
  {
    delete _instance;
    _instance = 0x0;
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the mutex.
//
///////////////////////////////////////////////////////////////////////////////

Database::Mutex &Database::mutex() const
{
  return *_mutex;
}


///////////////////////////////////////////////////////////////////////////////
//
//  Clear the database.
//
///////////////////////////////////////////////////////////////////////////////

void Database::clear()
{
  Guard guard ( this );
  _root->clear();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Accept the visitor.
//
///////////////////////////////////////////////////////////////////////////////

void Database::accept ( Usul::Registry::Visitor *v )
{
  if ( 0x0 != v )
  {
    v->visit ( this );
  }
}


///////////////////////////////////////////////////////////////////////////////
//
//  Operator to return the child with the name. Creates child nodes as needed.
//
///////////////////////////////////////////////////////////////////////////////

Node &Database::operator [] ( const std::string &name )
{
  Guard guard ( this );
  return (*_root)[name];
}


///////////////////////////////////////////////////////////////////////////////
//
//  Operator to return the child with the path. Creates child nodes as needed.
//
///////////////////////////////////////////////////////////////////////////////

Node &Database::operator [] ( const Node::Path &path )
{
  Guard guard ( this );
  return (*_root)[path];
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the root.
//
///////////////////////////////////////////////////////////////////////////////

Usul::Registry::Node *Database::root()
{
  Guard guard ( this );
  return _root.get();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Get the root.
//
///////////////////////////////////////////////////////////////////////////////

const Usul::Registry::Node *Database::root() const
{
  Guard guard ( this );
  return _root.get();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Convert the given string to a legal tag.
//
///////////////////////////////////////////////////////////////////////////////

std::string Database::convertToTag ( const std::string &s ) const
{
  // Re-entrant

  std::string tag ( s );

  std::replace ( tag.begin(), tag.end(), ' ',  '_' );
  std::replace ( tag.begin(), tag.end(), '/',  '_' );
  std::replace ( tag.begin(), tag.end(), '\\', '_' );
  std::replace ( tag.begin(), tag.end(), ':',  '_' );
  std::replace ( tag.begin(), tag.end(), '.',  '_' );
  std::replace ( tag.begin(), tag.end(), '-',  '_' );

  return tag;
}
